/*    
    OpenMheg - A free MHEG-5 library
    Copyright (C) 2008 Dharmesh Malam

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;

using System.Collections;
using Core.Model.Data.Variables;
using Core.Model.Data.Type;
using Core.Model.Data.Generics;
using Core.Model.Data;
using Core.Model;

namespace Core.Model.Groups
{
    public class Application : Group
    {
        #region  Exchanged Attributes

        private Core.Model.Actions.Action onSpawnCloseDown;

        public Core.Model.Actions.Action OnSpawnCloseDown
        {
            get { return onSpawnCloseDown; }
            set { onSpawnCloseDown = value; }
        }
        private Core.Model.Actions.Action onRestart;

        public Core.Model.Actions.Action OnRestart
        {
            get { return onRestart; }
            set { onRestart = value; }
        }

        #endregion

        #region  Default attributes

        private int characterSet = 10;

        public int CharacterSet
        {
            get { return characterSet; }
            set { characterSet = value; }
        }

        private GenericColour originalBackgroundColour = Engine.MHEGConstants.DefaultBackgroundColour;

        public GenericColour OriginalBackgroundColour
        {
            get { return originalBackgroundColour; }
            set { originalBackgroundColour = value; }
        }
        private GenericColour originaltextColour = Engine.MHEGConstants.DefaultTextColour;

        public GenericColour OriginalTextColour
        {
            get { return originaltextColour; }
            set { originaltextColour = value; }
        }
        private FontAttributes originalfontAttributes = Engine.MHEGConstants.DefaultFontAttributes;

        public FontAttributes OriginalFontAttributes
        {
            get { return originalfontAttributes; }
            set { originalfontAttributes = value; }
        }

        private int bitmapContentHook = Util.DefaultContentHooks.PngContentHook;

        public int BitmapContentHook
        {
            get { return bitmapContentHook; }
            set { bitmapContentHook = value; }
        }
        
        private int streamContentHook = Util.DefaultContentHooks.BroadcastStreamContentHook;

        public int StreamContentHook
        {
            get { return streamContentHook; }
            set { streamContentHook = value; }
        }

        private int lineArtContentHook = Util.DefaultContentHooks.LineArtContentHook;

        public int LineArtContentHook
        {
            get { return lineArtContentHook; }
            set { lineArtContentHook = value; }

        }
        private int textContentHook = Util.DefaultContentHooks.TextContentHook;

        public int TextContentHook
        {
            get { return textContentHook; }
            set { textContentHook = value; }
        }

        private GenericColour buttonRefColour =  new GenericColour( new Colour( 31, 31, 31,0 ) );

        public GenericColour ButtonRefColour
        {
            get { return buttonRefColour; }
            set { buttonRefColour = value; }
        }
        private GenericColour highlightRefColour = new GenericColour( new Colour( 31, 31, 31,0 ) );

        public GenericColour HighlightRefColour
        {
            get { return highlightRefColour; }
            set { highlightRefColour = value; }
        }
        private GenericColour sliderRefColour = new GenericColour( new Colour( 31, 31, 31,0 ) );

        public GenericColour SliderRefColour
        {
            get { return sliderRefColour; }
            set { sliderRefColour = value; }
        }

        #endregion

        #region  Internal Attributes

        private int lockCount = 0;

        public int LockCount
        {
            get { return lockCount; }
            private set 
            {
                lockCount = value < 0 ? 0 : value; 
            }
        }


        public override void InittInternalAttributes ()
        {
            base.InittInternalAttributes();
        }

        #endregion


        #region  Event processing


        public override void Destroy ()
        {

            base.Destroy();

            if ( Engine.MHEGEngine.Instance.ActiveApplication.Equals( this ) )
                Engine.MHEGEngine.Instance.ActiveApplication = null;
        }

        #endregion

        #region  Actions

        public void StorePersistent(Core.Model.Data.Variables.BooleanVariable storeSucceeded, List<ObjectRef> inVariables, OctetString outFileName)
        {
            storeSucceeded.Value = false;
            ArrayList file = new ArrayList( inVariables.Count );

            foreach ( ObjectRef reference in inVariables )
            {
               Core.Model.Data.Variables.Variable v = Engine.MHEGEngine.Instance.Find( reference ) as Variable;

                if ( v != null )
                {
                    file.Add( v.Data );
                }
                else
                {
                    log.Error( "Trying to store not existing data ("+reference+")." );
                    return;
                }
            }
            storeSucceeded.Value = Engine.MHEGEngine.Instance.StoreData( file, outFileName );
        }

        public void ReadPersistent(BooleanVariable readSucceeded, List<ObjectRef> outVariables, OctetString inFileName)
        {
            readSucceeded.Value = false;

            ArrayList data = Engine.MHEGEngine.Instance.GetData( inFileName );

            if ( data != null )
            {
                if ( data.Count != outVariables.Count ) log.Warn( "Different number of out varibles cf data stored, saving mathing set(Stored:"
                                                                +data.Count+" Vars:"+outVariables.Count+")." );
                for ( int i = 0 ; i < outVariables.Count && i < data.Count ; i++ )
                {
                    Variable variable = Engine.MHEGEngine.Instance.Find( outVariables [i] ) as Variable;
                    if ( variable != null )
                        variable.Data = data [i];
                    else
                    {
                        log.Error( "Trying to read persistant to non variable! ("+inFileName+":"+data [i]+" to "+outVariables [i]+")." );
                        return;
                    }
                }

            }
            else
            {
                log.Warn( "Could not find data in persistant store ("+inFileName+")" );
                return;
            }

            readSucceeded.Value = true;
        }


        public void Launch ()
        {
            log.Info( "Launching Application: "+this+"." );

            if ( Engine.MHEGEngine.Instance.ActiveScene != null )
                Engine.MHEGEngine.Instance.ActiveScene.Destroy();

            if ( Engine.MHEGEngine.Instance.ActiveApplication != null )
                Engine.MHEGEngine.Instance.ActiveApplication.Destroy();

            Engine.MHEGEngine.Instance.ClearActiveApp();
            Engine.MHEGEngine.Instance.ActiveScene = null;
            Engine.MHEGEngine.Instance.ActiveApplication = this;

            Activate();

            log.Info( "Launched Application: "+this+"." );

        }

        public void Spawn ()
        {
            log.Info( "Spawning: "+ Engine.MHEGEngine.Instance.ActiveApplication +" => "+this+" ." );
           
            if ( Engine.MHEGEngine.Instance.ActiveApplication != null )
            {
                Engine.MHEGEngine.Instance.DoActions( Engine.MHEGEngine.Instance.ActiveApplication.OnSpawnCloseDown );

                Engine.MHEGEngine.Instance.ApplicationStack.Push( Engine.MHEGEngine.Instance.ActiveApplication.ObjectIdentifier );
            }

            Launch();

        }

        public void Quit ()
        {

            if ( Engine.MHEGEngine.Instance.ActiveApplication.Equals( this ) )
            {
                log.Info( "Quiting application: "+this+"." );
                if(Engine.MHEGEngine.Instance.ActiveScene != null)
                    Engine.MHEGEngine.Instance.ActiveScene.Destroy();

                Destroy();

                Engine.MHEGEngine.Instance.RunActions();

                if ( Engine.MHEGEngine.Instance.ApplicationStack.Count > 0 )
                {
                    
                    ObjectRef reference = Engine.MHEGEngine.Instance.ApplicationStack.Peek();
                    
                    log.Info( "Restarting application: "+ reference+"." );

                    // try
                    //{
                    Application app = ( Application ) Engine.MHEGEngine.Instance.Find( reference );
                    //app.activate();
                    app.Launch();
                    Engine.MHEGEngine.Instance.ApplicationStack.Pop();
                    Engine.MHEGEngine.Instance.DoActions( app.OnRestart );
                    

                    // }
                    //catch (ClassCastException cce)
                    //{
                    // log.severe("Could not deference an object reference into an Application object");
                    // }
                }
                else
                    Engine.MHEGEngine.Instance.Quit();
            }


        }

        public void LockScreen ()
        {
            LockCount++;

            if ( LockCount > 0 )
            {
                Engine.MHEGEngine.Instance.DisplayStack.LockScreen();
            }
        }

        public void UnlockScreen ()
        {
            LockCount--;

            if ( LockCount == 0 )
            {
                Engine.MHEGEngine.Instance.DisplayStack.UnlockScreen();
            }
        }

        public void GetEngineSupport(OctetString feature, BooleanVariable answer)
        {
            String feat = feature.StringValue.ToLower();


            if ( feat.StartsWith( "ancillaryconnections" ) || feat.StartsWith( "aco" ) )
                answer.Value = false;
            else if ( feat.StartsWith( "applicationstacking" ) || feat.StartsWith( "ast" ) )
                answer.Value = true;
            else if ( feat.StartsWith( "cloning" ) || feat.StartsWith( "clo" ) )
                answer.Value = true;
            else if ( feat.StartsWith( "freemovingcursor" ) || feat.StartsWith( "fmc" ) )
                answer.Value = false;
            else if ( feat.StartsWith( "multipleaudiostreams" ) || feat.StartsWith( "mas" ) )
                answer.Value = feat.EndsWith( "(0)" ) || feat.EndsWith( "(1)" );
            else if ( feat.StartsWith( "overlappingvisibles" ) || feat.StartsWith( "ovv" ) )
                answer.Value = true;
            else if ( feat.StartsWith( "scaling" ) || feat.StartsWith( "sca" ) )
                answer.Value = false;
            else if ( feat.StartsWith( "sceneaspectratio" ) || feat.StartsWith( "sar" ) )
                answer.Value = feat.EndsWith( "(4,3)" ) || feat.EndsWith( "(16,9)" );
            else if ( feat.StartsWith( "scenecoordinatesystem" ) || feat.StartsWith( "scs" ) )
                answer.Value = feat.EndsWith( "(720,576)" );//|| feat.EndsWith( "(1,1)");
            else if ( feat.StartsWith( "trickmodes" ) || feat.StartsWith( "trm" ) )
                answer.Value = false;
            else if ( feat.StartsWith( "videoscaling" ) || feat.StartsWith( "vsc" ) )
                answer.Value = feat.EndsWith( "(10,720,576)" ) || feat.EndsWith( "(10,360,288)" ) || feat.EndsWith( "(10,1440,1152)" );
            else if ( feat.StartsWith( "bitmapscaling" ) || feat.StartsWith( "bsc" ) )
                answer.Value = feat.EndsWith( "(2,720,576)" ) || feat.EndsWith( "(2,360,288)" ) || feat.EndsWith( "(2,1440,1152)" );
            else if ( feat.StartsWith( "videodecodeoffset" ) || feat.StartsWith( "vdo" ) )
                answer.Value = feat.EndsWith( "(10,0)" ) || feat.EndsWith( "(10,1)" );
            else if ( feat.StartsWith( "bitmapdecodeoffset" ) || feat.StartsWith( "bdo" ) )
                answer.Value = feat.EndsWith( "(2,0)" ) || feat.EndsWith( "(2,1)" );
            else if ( feat.StartsWith( "ukengineprofile" ) || feat.StartsWith( "uep" ) )
                answer.Value =  feat.EndsWith( "(2)" ) ;//|| feat.EndsWith("(xxxnnn)");
            else if ( feat.StartsWith( "dvr" ) )
                answer.Value = false;//feat.EndsWith( "(+)" );
            else
            {
                answer.Value = false;
                throw new Exception( "Oii" );
                log.Error( "GetEngineSupport: Asked for unknown feature ("+feature+"), Returning false..." );
            }

            log.Info( "GetEngineSupport: Asked for ("+feature+"), Answer = "+answer.Value+"." );
        }

        #endregion
    }
}
